'''
Author: 蚢
Date: 2021-06-02 10:54:15
Description: 
    1 改变对象的字符串显示
    2 自定义字符串的格式化
    3 让对象支持上下文管理协议（with语句）
    4 创建大量对象时节省内存方法
    5 在类中封装属性名
    6 创建可管理的属性
    7 调用父类方法
    8 子类中扩展property
    9 创建新的类或实例属性
'''


from os import WIFCONTINUED


class Pair():
    '''
    __repr__() 方法返回一个实例的代码表示形式，通常用来重新构造这个实例。
    内置的 repr() 函数返回这个字符串，跟我们使用交互式解释器显示的值是一样的。
    __str__() 方法将实例转换为一个字符串，使用 str() 或 print() 函数会输出这个字
    符串。
    '''
    def __init__(self, x, y) -> None:
        self.x = x
        self.y = y

    def __repr__(self) -> str:
        return 'Pair{%r}, {%r}' % (self.x, self.y)

    def __str__(self) -> str:
        return '这{0.x!s}, {0.y!s}'.format(self)

    def __format__(self, format_spec: str) -> str:
        return '格式化{%r}, {%r}' % (self.x, self.y)

p = Pair(3, 4)        
print(p)
print("P's format:{0}".format(p))


# 让一个对象兼容with语句，需要实现__enter__()和__exit__()方法。
# 自定义一个上下文管理器，实现对文本的自动关闭。
class OpenFile:
    def __init__(self, fileName, openMode) -> None:
        self.fileName = fileName
        self.openMode = openMode
        self.file = None

    def __enter__(self):
        self.file = open(file=self.fileName, mode=self.openMode)
        
    def __exit__(self, exc_ty, exc_val, tb):
        self.file.close()
        self.file = None

with OpenFile('file.txt', 'r') as f:
    pass


__slots__ = ['year', 'month', 'day']
# 使用slots 会对实例使用一种更加紧凑的内部表示，但就无法扩展新的属性了。

# Python并没有访问控制，使用命名来规约以达到效果。
# 但使用__可以通用继承并且无法被覆盖。

# 方法名字都必须一样
class Person:
    def __init__(self, first_name) -> None:
        self.first_name = first_name

    @property # get函数，使first_name成为一个属性
    def first_name(self):
        return self._first_name

    @first_name.setter # 给first_name增加setter函数
    def first_name(self, value):
        if not isinstance(value, str):
            raise TypeError('Expected a string')
        self._first_name = value

    @first_name.deleter
    def first_name(self):
        raise AttributeError("Can't deleete attribute")

a = Person('hang')
print(a.first_name)


# 调用父类的方法可以用super()
class A():
    def __init__(self) -> None:
        self.x = 0

    def spam(self):
        print('A.spam')

class B(A):
    def __init__(self) -> None:
        super().__init__()  # 确保父类被正确的初始化
        self.y = 1

    def spam(self):
        print('B.spam')
        super().spam()

b = B()
print(B.__mro__) # 使用类.__mro__可以查看类的线性继承（PYTHON的MRO列表）。


class SubPerson(Person):
    @property
    def name(self):
        print('Get')
        return super().first_name

    @name.setter
    def name(self, value):
        print('Set ', value)
        super(SubPerson, SubPerson).first_name.__set__(self, value)

    @name.deleter
    def name(self):
        print('Delet')
        super(SubPerson, SubPerson).first_name.__delete__(self)

s = SubPerson('Name')    
print(s.name)
s.name = 'Larry'

